﻿using System;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;

namespace Quakk.Twitter
{
    public class Tweet
    {
        private Image userImage;
        public event EventHandler UserImageChanged;

        public string Username
        {
            get; set;
        }

        public string DisplayName
        {
            get; set;
        }

        public DateTime TweetDateTime
        {
            get; set;
        }

        public string Message
        {
            get; set;
        }

        public string Source
        {
            get; set;
        }

        [XmlIgnore]
        public Image UserImage
        {
            get
            {
                return userImage;
            }
            set
            {
                userImage = value;
                if(UserImageChanged != null)
                {
                    UserImageChanged(this, EventArgs.Empty);
                }
            }
        }

        public string UserImageUrl
        {
            get; set;
        }

        public bool IsReply
        {
            get; set;
        }

        public bool IsSelfTweet
        {
            get; set;
        }

        public Tweet()
        { }

        public Tweet(XmlNode tweetXml, string username)
        {
            ParseXml(tweetXml, username);

            // Check to see if this is a Tweet send by this user
            if(username.ToLower() == Username.ToLower())
            {
                IsSelfTweet = true;
            }
        }

        /// <summary>
        /// Returns the first Url discovered in the Message body, if one exists
        /// </summary>
        /// <returns>The first Url</returns>
        public string ExtractUrl()
        {
            Match match = Regex.Match(" " + Message, "((http://|www\\.)[^\\s]+)");

            if(!match.Success)
            {
                return "";
            }

            return match.Groups[1].Value;
        }

        /// <summary>
        /// Tries to parse the given Xml Tree and populates the instances properties with what it finds
        /// </summary>
        /// <param name="xml">The XmlNode that is the start of the tweet Xml Tree</param>
        /// <param name="username">The username to use when identifying replies</param>
        private void ParseXml(XmlNode xml, string username)
        {
            XmlNode user = FindXmlChildNode(xml, "user") ?? FindXmlChildNode(xml, "sender");
            string tweetTime = GetXmlChildNodeText(xml, "created_at");

            DisplayName = GetXmlChildNodeText(user, "name");
            Username = GetXmlChildNodeText(user, "screen_name");
            UserImageUrl = GetXmlChildNodeText(user, "profile_image_url");
            Message = GetXmlChildNodeText(xml, "text");
            Source = GetXmlChildNodeText(xml, "source");
            TweetDateTime = ParseDate(tweetTime);

            // If the body contains the user's username preceded by an '@' then mark it as a reply
            IsReply = (Message.ToLower().IndexOf("@" + username) > -1) ? true : false;
        }

        /// <summary>
        /// Parse the date format used in the Twitter API into a .NET DateTime object
        /// </summary>
        /// <param name="dateString">The date string obtained from a Twitter feed</param>
        /// <returns>The resulting DateTime object</returns>
        private static DateTime ParseDate(string dateString)
        {
            // Pattern to match Date Format returned by Twitter: Mon Sep 15 06:39:41 +0000 2008
            const string pattern = @"\w{3} (?<Month>\w{3}) (?<Day>\d{2}) (?<Time>\d{2}:\d{2}:\d{2}) +0000 (?<Year>\d{4})";
            Match match = Regex.Match(dateString, pattern);

            if(!match.Success)
            {
                return DateTime.Now;
            }

            DateTime date = DateTime.Parse(match.Groups["Day"].Value + " " +
                                           match.Groups["Month"].Value + " " +
                                           match.Groups["Year"].Value + " " +
                                           match.Groups["Time"].Value);

            // Comes in GMT time I believe, so we use this to convert to the system's local time 
            date = TimeZone.CurrentTimeZone.ToLocalTime(date);

            return date;
        }

        /// <summary>
        /// Returns the first child node of the XmlNode provided that matches the given name
        /// </summary>
        /// <param name="xmlNode">The parent XmlNode</param>
        /// <param name="childNodeName">The name of the child node to return</param>
        /// <returns>The matching child node, or null if none exist</returns>
        private static XmlNode FindXmlChildNode(XmlNode xmlNode, string childNodeName)
        {
            foreach (XmlNode child in xmlNode.ChildNodes)
            {
                if (child.Name == childNodeName)
                    return child;
            }

            return null;
        }

        /// <summary>
        /// Returns the InnerText value of the first child node to match the given name
        /// </summary>
        /// <param name="xmlNode">The parent XmlNode</param>
        /// <param name="childNodeName">The name of the child node to match</param>
        /// <returns>The InnerText value of the matching node, or an empty string if no matching children exist</returns>
        private static string GetXmlChildNodeText(XmlNode xmlNode, string childNodeName)
        {
            XmlNode node = FindXmlChildNode(xmlNode, childNodeName);

            return node != null ? node.InnerText : "";
        }
    }
}
